﻿#region CREDIT & LICENSE
/*******************************************
 * CREDIT: 
 * http://www.ROMPROS.com 
 * Tremendously helpful website, also would
 * like to give special thanks to:
 * 
 * Roverser - for the great effort on a c repository 
 * that most of this was ported from. http://code.google.com/p/rombot/
 * 
 * ROMeo - for the great amount of information shared
 * all across the rompros site. http://www.rompros.com/member.php?u=1901
 * 
 * 
 * LICENSE:
 *  
 * RomAPI is c# library is used to communicate directly with
 * the Runes Of Magic game client. 
 * 
 * Copyright (C) 2010  digitalxarts@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 *******************************************/
#endregion#endregion

using System;
using Magic;
using RoMFramework.RomAPI.Objects;
using RoMFramework.Hacks;
using System.IO;

namespace RoMFramework.RomAPI
{
    public class RomClient
    {
		/// <summary>
		/// World holds all the information that is part of 
		/// the players environment.
		/// </summary>
        public RomWorld World;
		/// <summary>
		/// Player is the reference to the actual player that
		/// </summary>
        public RomPlayer Player;
		/// <summary>
		/// BlackMagic is the memory manipulation class that allows 
		/// us to read/write to the client.exe
		/// </summary>
        public BlackMagic RoM { get; set; }

        /// <summary>
        /// Pointers is the PointerManager class that contains the addresses found from patterns.xml
        /// </summary>
        public PointerManager Pointers;

        /// <summary>
        /// Hacks is the HackManager class that contains methods to enable and disable hacks!
        /// </summary>
        public HackManager Hacks;

        public string PatternFile;

        public uint m_BasePlayerAddress;
        public uint m_PlayerAddress;
        
        
        /// <summary>
        /// Attaches the client to the specified RoM process
        /// </summary>
        /// <param name="process">The process ID to attach to</param>
        /// <param name="patternFile">The filename of the pattern file (defaults to patterns.xml</param>
        public RomClient(int process, string patternFile = "patterns.xml")
        {
            CheckConfig();
            PatternFile = patternFile;
            AttachToSpecificRoM(process);
            SetUp();
        }

        private void CheckConfig()
        {
            if (File.Exists(System.AppDomain.CurrentDomain.FriendlyName.ToString() + ".config")) return;
            string[] lines = {
                                 "<configuration>", "<startup useLegacyV2RuntimeActivationPolicy=\"true\">",
                                 "<supportedRuntime version=\"v4.0\"/>", "</startup>", "</configuration>"
                             };
            System.IO.File.WriteAllLines(
                @".\" + System.AppDomain.CurrentDomain.FriendlyName.ToString() + ".config", lines);
        }

        /// <summary>
        /// Attaches the client to the specified RoM process
        /// </summary>
        /// <param name="process">The process ID to attach to</param>
        private void AttachToSpecificRoM(int process)
        {
            try
            {
                Console.Instance.AddLine("Attaching...");
                RoM = new BlackMagic(process);
                Console.Instance.AddLine(String.Format("RoM Found, Proccess ID is {0}", RoM.ProcessId));
            }
            catch (Exception ex)
            {
                Console.Instance.AddLine(ex.Message);
            }
            
        }

        /// <summary>
        /// Attaches to the first available RoM process
        /// <param name="patternFile">The filename of the pattern file (defaults to patterns.xml</param>
        /// </summary>
        public RomClient(string patternFile = "patterns.xml")
        {
            CheckConfig();
            PatternFile = patternFile;
            AttachToFirstAvailableRoM();
            SetUp();
        }

        /// <summary>
        /// Attaches to the first available RoM process
        /// </summary>
        private void AttachToFirstAvailableRoM()
        {
            try
            {
                Console.Instance.AddLine("Attaching...");
                RoM = new BlackMagic(Magic.SProcess.GetProcessFromClassname(Common.ROM_WINDOW_CLASS_NAME));
                if (RoM.IsProcessOpen)
                {
                    Console.Instance.AddLine(String.Format("RoM Found, Proccess ID is {0}", RoM.ProcessId));
                }
                else
                {
                    throw new Exception("Please start RoM before Loading");
                }
                
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Please make sure RoM is running before doing anything.", "Start RoM",
                    System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.None);
                Console.Instance.AddLine(ex.Message);
            }
        }

        /// <summary>
        /// Initialises this Client
        /// </summary>
        private void SetUp()
        {
            try
            {
                if (String.IsNullOrEmpty(PatternFile) || PatternFile.Trim().Length == 0 || !File.Exists(PatternFile))
                    throw new Exception("The specified pattern file does not exist");
                //Find the Pointers
                Console.Instance.AddLine("Initialising Pointer Scanner");
                Pointers = new PointerManager(RoM);
                Pointers.SearchPatterns(PatternFile);
                //Read the Player base pointer
                m_BasePlayerAddress = RoM.ReadUInt(Pointers.PointerToUint("CharacterBasePointer"));
                m_PlayerAddress = m_BasePlayerAddress + Pointers.PointerToUint("CharacterOffset");
                //Creating a new Player for this client (passing reference to the client).
                Player = new RomPlayer(this, m_PlayerAddress, Pointers);
                //Creating a new HackManager for this client (passing reference to the client).
                Hacks = new HackManager(this);
                
            }
            catch (Exception ex)
            {
                /* 
                 * We failed to attach to the client.exe process. 
                 * Use the CanAttachToProcess to validate if this process
                 * can be attached. Or finding the pointers failed.
                 */
                Console.Instance.AddLine(ex.Message);
                throw ex;
                
            }
        }
        
        /// <summary>
		/// This function is used to validate if we can attach to the client process
		/// </summary>
		/// <param name="process">The Process ID</param>
		/// <returns>True/False if we can attach to process.</returns>
		public static bool CanAttachToProcess(int process)
		{
			bool isAttachable = false;
			try
			{
				var magic = new BlackMagic(process);
				isAttachable = true;
				//add extended logic to see if game is player is in game, and not login screen
                magic.Close();
			}
			catch(Exception)
			{
				isAttachable = false;
			}
			return isAttachable;
		}
		
    }
    
    

}
